package com.game.model;

import com.game.global.Const;
import com.game.main.GameContext;
import com.game.util.ImageUtil;
import com.game.util.PropertiesUtil;

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @Author: tjc
 * @description
 * @Date Created in 15:20 2021-08-01
 */
public class Hero extends Tank implements KeyListener {

    int upOrDown = Const.DIRECTION_NONE;
    int leftOrRight = Const.DIRECTION_NONE;
    int shootCmd = 0;
    AtomicBoolean keepMove = new AtomicBoolean(false);
    Player player;

    private static Set<Integer> directionKeys = new HashSet<Integer>() {{
        add(KeyEvent.VK_W);
        add(KeyEvent.VK_S);
        add(KeyEvent.VK_A);
        add(KeyEvent.VK_D);
    }};

    private static Map<Integer, Integer> directionMap = new HashMap<Integer, Integer>() {{
        put(KeyEvent.VK_W, Const.DIRECTION_UP);
        put(KeyEvent.VK_S, Const.DIRECTION_DOWN);
        put(KeyEvent.VK_A, Const.DIRECTION_LEFT);
        put(KeyEvent.VK_D, Const.DIRECTION_RIGHT);
    }};


    public Hero() {
        SIZE_X = PropertiesUtil.loadInt("hero.width");
        SIZE_Y = PropertiesUtil.loadInt("hero.length");
        speed = PropertiesUtil.loadInt("hero.speed");
        curDirection = Const.DIRECTION_UP;
    }

    public Hero(int x, int y, int direction) {
        this();
        this.localX = x;
        this.localY = y;
        curDirection = direction;
    }

    @Override
    public void draw(Graphics g) {
        move();
        switch (this.curDirection) {
            case Const.DIRECTION_UP:
                g.drawImage(ImageUtil.heroImages[0], localX, localY, SIZE_X, SIZE_Y, null);
                break;
            case Const.DIRECTION_DOWN:
                g.drawImage(ImageUtil.heroImages[1], localX, localY, SIZE_X, SIZE_Y, null);
                break;
            case Const.DIRECTION_LEFT:
                g.drawImage(ImageUtil.heroImages[2], localX, localY, SIZE_X, SIZE_Y, null);
                break;
            case Const.DIRECTION_RIGHT:
                g.drawImage(ImageUtil.heroImages[3], localX, localY, SIZE_X, SIZE_Y, null);
                break;
            default:
                throw new RuntimeException("方向参数错误!");
        }
    }

    //
    boolean checkDirection(int direction) {
        //TODO 还是不完美，差强人意吧
        if (direction == Const.DIRECTION_UP || direction == Const.DIRECTION_DOWN) {
            setDirection(direction);
            this.upOrDown = direction;
        }
        if (direction == Const.DIRECTION_RIGHT || direction == Const.DIRECTION_LEFT) {
            setDirection(direction);
            this.leftOrRight = direction;
        }
        return false;
    }


    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        if(!alive()) {
            return;
        }
        if (isDirectionKey(e)) {
            int pressDirection = directionMap.get(e.getKeyCode());
            checkDirection(pressDirection);
            keepMove.set(true);
        }
        else if (isShootKey(e)) {
            shoot();
        }
    }

    private boolean isDirectionKey(KeyEvent e) {
        return directionKeys.contains(e.getKeyCode());
    }

    private boolean isShootKey(KeyEvent e) {
        return e.getKeyCode() == KeyEvent.VK_J;
    }

    @Override
    public void keyReleased(KeyEvent e) {
        if (!isDirectionKey(e))
            return;

        int d = directionMap.get(e.getKeyCode());
        // 上下，左右各位一组方向键，按住两组方向键时，松开一个键，会保持剩下一组的方向
        if (d == Const.DIRECTION_UP || d == Const.DIRECTION_DOWN) {
            upOrDown = Const.DIRECTION_NONE;
            if (leftOrRight != Const.DIRECTION_NONE) {
                this.curDirection = leftOrRight;
            }
        }
        if (d == Const.DIRECTION_LEFT || d == Const.DIRECTION_RIGHT) {
            leftOrRight = Const.DIRECTION_NONE;
            if (upOrDown != Const.DIRECTION_NONE) {
                this.curDirection = upOrDown;
            }
        }

        if (this.upOrDown == Const.DIRECTION_NONE && this.leftOrRight == Const.DIRECTION_NONE)
            keepMove.set(false);
    }

    @Override
    public void move() {
        if (!keepMove.get() || isBlocking()) {
            return;
        }
        switch (this.curDirection) {
            case Const.DIRECTION_UP:
                localY = localY - speed;
                break;
            case Const.DIRECTION_DOWN:
                localY = localY + speed;
                break;
            case Const.DIRECTION_LEFT:
                localX = localX - speed;
                break;
            case Const.DIRECTION_RIGHT:
                localX = localX + speed;
                break;
            default:
        }
    }

    @Override
    public void start() {
    }

    @Override
    public void destroy() {
        super.destroy();
        player.reduceLife();
    }

    @Override
    public int getTankType() {
        return Tank.T_HERO;
    }

    @Override
    public void init() {
        GameContext context = GameContext.getContext();
        this.alive = new AtomicBoolean(true);
        this.player = context.getPlayer();
        context.addKeyListener(this);
    }

    @Override
    public boolean alive() {
        return alive.get();
    }

    public void setPlayer(Player player) {
        this.player = player;
    }
}
